package com.egg.basic.service.captcha;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.ObjectUtil;
import com.egg.basic.config.captcha.CaptchaConfig;
import com.egg.basic.enums.captcha.CaptchaStyleEnum;
import com.egg.basic.enums.captcha.CaptchaTypeEnum;
import com.egg.basic.model.response.CaptchaInfo;
import com.egg.common.redis.util.RedisUtil;
import com.egg.common.spring.util.SpringContextUtil;
import com.egg.common.util.IdGenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;


@Slf4j
@Service
public class CaptchaService {


    @Autowired
    private CaptchaConfig captchaConfig;


    /**
     * 构建验证码redis缓存KEY
     *
     * @param id
     * @return
     */
    private String buildCaptchaImageKey(String id) {
        return String.format("basic:captcha:image:%s", id);
    }

    /**
     * 校验验证码
     *
     * @param id
     * @param code
     * @return
     */
    public boolean verify(String id, String code) {
        if (!captchaConfig.getEnabled()) {
            return true;
        }
        if (ObjectUtil.isEmpty(code)) {
            return false;
        }
        String key = buildCaptchaImageKey(id);
        String redisLoginCaptcha = RedisUtil.get(key);
        if (ObjectUtil.isEmpty(redisLoginCaptcha)) {
            return false;
        }
        boolean result = Objects.equals(code, redisLoginCaptcha);
        if (result) {
            RedisUtil.delete(key);
        }
        return result;
    }

    private String converBase64(String source) {
        String pngBase64 = source.trim().replaceAll("\n", "").replaceAll("\r", "");
        //转换成base64串
        return "data:image/png;base64," + pngBase64;
    }

    /**
     * 生产验证码
     *
     * @return
     * @throws IOException
     */
    public CaptchaInfo generate() {
        CaptchaInfo captchaInfo = new CaptchaInfo();
        captchaInfo.setEnabled(false);
        if (!captchaConfig.getEnabled()) {
            return captchaInfo;
        }
        Optional<CaptchaTypeEnum> captchaType = CaptchaTypeEnum.findByCode(captchaConfig.getType());
        if (!captchaType.isPresent()) {
            log.error("验证码类型配置异常, 请检查相关配置");
            return captchaInfo;
        }
        Optional<CaptchaStyleEnum> captchaStyle = CaptchaStyleEnum.findByCode(captchaConfig.getStyle());
        if (!captchaStyle.isPresent()) {
            log.error("验证码样式配置异常, 请检查相关配置");
            return captchaInfo;
        }
        AbstractCaptcha captcha = SpringContextUtil.getBean(captchaStyle.get().getClazz());
        CodeGenerator codeGenerator = SpringContextUtil.getBean(captchaType.get().getClazz());
        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        String code = captcha.getCode();
        if (CaptchaTypeEnum.MATH == captchaType.get()) {
            ExpressionParser parser = new SpelExpressionParser();
            Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
            code = exp.getValue(String.class);
        }
        String id = IdGenUtil.strId();
        Integer expireSeconds = captchaConfig.getTime();
        LocalDateTime expireDate = LocalDateTime.now().plusSeconds(expireSeconds);
        // 放入缓存
        RedisUtil.set(buildCaptchaImageKey(id), code, expireSeconds);
        // 构建返回
        captchaInfo.setEnabled(captchaConfig.getEnabled());
        captchaInfo.setType(captchaConfig.getType());
        captchaInfo.setId(id);
        captchaInfo.setBase64(converBase64(captcha.getImageBase64()));
        captchaInfo.setExpireDate(expireDate);
        captchaInfo.setExpireSeconds(expireSeconds);
        return captchaInfo;
    }


}